home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / hard / drivr / cyberx10.lha / CyberX10 / Source / CyberX10.c < prev    next >
C/C++ Source or Header  |  1992-11-06  |  11KB  |  543 lines

  1. /*
  2.  * CyberX10.c
  3.  *
  4.  * Copyright © 1992 by Christopher A. Wichura (caw@miroc.chi.il.us)
  5.  * All Rights Reserved.
  6.  */
  7.  
  8.  /* stuff for our ReadArgs() call */
  9.  
  10. #define ARG_TEMPLATE "TARGETS/M,ON/S,OFF/S,DIM/K/N,BASEHC/K,SETCLOCK/S,DIAG/S,DOWNLOAD/K,UPLOAD/K,DEVICE/K,UNIT/K/N,ATTEMPT/S"
  11. enum ReadArgsArray {
  12.     ARG_TARGETS,
  13.     ARG_ON,
  14.     ARG_OFF,
  15.     ARG_DIM,
  16.     ARG_BASEHC,
  17.     ARG_SETCLOCK,
  18.     ARG_DIAG,
  19.     ARG_DOWNLOAD,
  20.     ARG_UPLOAD,
  21.     ARG_DEVICE,
  22.     ARG_UNIT,
  23.     ARG_ATTEMPT,
  24.     ARG_sizeof
  25. };
  26.  
  27. const UBYTE HouseCode[16] =
  28. {0x60, 0xE0, 0x20, 0xA0, 0x10, 0x90, 0x50, 0xD0, 0x70, 0xF0, 0x30, 0xB0, 0x00, 0x80, 0x40, 0xC0};
  29.  
  30. struct Library *IconBase;
  31. struct Library *UtilityBase;
  32.  
  33. struct LocaleInfo LocaleInfo;
  34. struct Locale *DefaultLocale;
  35.  
  36. int __regargs main(char *cmdptr, int cmdlen, struct WBStartup * WBMsg)
  37. {
  38.     STRPTR WBArgs;
  39.     STRPTR ArgHelp;
  40.     LONG index;
  41.     extern UBYTE __far arg_help[];
  42.     extern UBYTE __far copyright[];
  43.  
  44.     /*
  45.      * the first thing we do is try and open up the locale library and
  46.      * grab our catalog as we will need it if we want to print any error
  47.      * messages or other text
  48.      */
  49.  
  50.     if (LocaleInfo.li_LocaleBase = (APTR) OpenLibrary("locale.library", 38)) {
  51.         DefaultLocale = OpenLocale(NULL);    /* autodocs say this is
  52.                              * guarenteed a valid
  53.                              * return */
  54.         LocaleInfo.li_Catalog = OpenCatalogA(NULL, "CyberX10.catalog", NULL);
  55.     }
  56.  
  57.     /* try and open up utility.library */
  58.     if (UtilityBase = OpenLibrary("utility.library", 37)) {
  59.         if (ArgHelp = AllocVec(strlen(GetString(&LocaleInfo, MSG_ARG_HELP)) + strlen(GetString(&LocaleInfo, MSG_COPYRIGHT)) + strlen(PROGNAME) + strlen(VersionID) + 1, MEMF_CLEAR)) {
  60.             sprintf(ArgHelp, GetString(&LocaleInfo, MSG_ARG_HELP), PROGNAME, VersionID, GetString(&LocaleInfo, MSG_COPYRIGHT));
  61.  
  62.             if (WBMsg) {
  63.                 ErrorsToEzReq = TRUE;
  64.  
  65.                 if (IconBase = OpenLibrary("icon.library", 37)) {
  66.                     for (index = (WBMsg->sm_NumArgs != 1 ? 1 : 0); index < WBMsg->sm_NumArgs; index++) {
  67.                         if (WBArgs = WBtoCLIargs(&WBMsg->sm_ArgList[index], ARG_TEMPLATE)) {
  68.                             DoInstance(WBArgs, NULL);
  69.                             FreeVec(WBArgs);
  70.                         }
  71.                     }
  72.  
  73.                     CloseLibrary(IconBase);
  74.                 }
  75.             }
  76.             else
  77.                 DoInstance(NULL, ArgHelp);
  78.  
  79.             FreeVec(ArgHelp);
  80.         }
  81.  
  82.         CloseLibrary(UtilityBase);
  83.     }
  84.     else
  85.         ErrorMsg(MSG_COULDNT_OPEN, "utility.library");
  86.  
  87.     if (LocaleInfo.li_LocaleBase) {
  88.         CloseCatalog(LocaleInfo.li_Catalog);
  89.         CloseLocale(DefaultLocale);
  90.         CloseLibrary((struct Library *) LocaleInfo.li_LocaleBase);
  91.     }
  92. }
  93.  
  94.  /* actually proccess the argument line and do what was requested */
  95.  
  96. void DoInstance(STRPTR ArgLine, STRPTR ArgHelp)
  97. {
  98.     struct RDArgs *RArgs, *MyRArgs;
  99.     STRPTR ArgArray[ARG_sizeof];
  100.  
  101.     STRPTR SerDevice;
  102.     ULONG SerUnit;
  103.  
  104.     /* do the stuff needed to call ReadArgs to parse the command line */
  105.     memset(ArgArray, 0, sizeof(ArgArray));
  106.  
  107.     if (MyRArgs = AllocDosObject(DOS_RDARGS, TAG_DONE)) {
  108.         if (ArgLine) {
  109.             MyRArgs->RDA_Source.CS_Buffer = ArgLine;
  110.             MyRArgs->RDA_Source.CS_Length = strlen(ArgLine);
  111.             MyRArgs->RDA_Source.CS_CurChr = 0L;
  112.         }
  113.  
  114.         if (ArgHelp)
  115.             MyRArgs->RDA_ExtHelp = ArgHelp;
  116.         else
  117.             MyRArgs->RDA_Flags |= RDAF_NOPROMPT;
  118.  
  119.         if (RArgs = ReadArgs(ARG_TEMPLATE, (LONG *) & ArgArray, MyRArgs)) {
  120.             if (ArgArray[ARG_DEVICE])
  121.                 SerDevice = ArgArray[ARG_DEVICE];
  122.             else
  123.                 SerDevice = "serial.device";
  124.  
  125.             if (ArgArray[ARG_UNIT])
  126.                 SerUnit = *((LONG *) ArgArray[ARG_UNIT]);
  127.             else
  128.                 SerUnit = 0;
  129.  
  130.             if (OpenTimer()) {
  131.                 if (OpenSerial(SerDevice, SerUnit, (BOOL) ArgArray[ARG_ATTEMPT])) {
  132.                     if (ArgArray[ARG_ON])
  133.                         X10TurnOn((STRPTR *) ArgArray[ARG_TARGETS]);
  134.                     else if (ArgArray[ARG_OFF])
  135.                         X10TurnOff((STRPTR *) ArgArray[ARG_TARGETS]);
  136.                     else if (ArgArray[ARG_DIM])
  137.                         X10Dim((STRPTR *) ArgArray[ARG_TARGETS], *((LONG *) ArgArray[ARG_DIM]));
  138.                     else if (ArgArray[ARG_BASEHC])
  139.                         X10SetBaseHC(ArgArray[ARG_BASEHC]);
  140.                     else if (ArgArray[ARG_SETCLOCK])
  141.                         X10SetClock();
  142.                     else if (ArgArray[ARG_DIAG])
  143.                         X10Diagnostic();
  144.                     else if (ArgArray[ARG_DOWNLOAD])
  145.                         X10Download(ArgArray[ARG_DOWNLOAD]);
  146.                     else if (ArgArray[ARG_UPLOAD])
  147.                         X10Upload(ArgArray[ARG_UPLOAD]);
  148.                     else
  149.                         ErrorMsg(MSG_NOTHING_TO_DO);
  150.  
  151.                     CloseSerial();
  152.                 }
  153.                 else
  154.                     ErrorMsg(MSG_NO_SER_DEV, SerDevice, SerUnit);
  155.  
  156.                 CloseTimer();
  157.             }
  158.             else
  159.                 ErrorMsg(MSG_NO_TIMER);
  160.  
  161.             FreeArgs(RArgs);
  162.         }
  163.         else
  164.             PrintFault(IoErr(), PROGNAME);
  165.  
  166.         FreeDosObject(DOS_RDARGS, MyRArgs);
  167.     }
  168.     else
  169.         ErrorMsg(MSG_NO_RDARGS);
  170. }
  171.  
  172.  /* turn on the selected X10 units */
  173.  
  174. void X10TurnOn(STRPTR * Targets)
  175. {
  176.     OnOffDimHandler(Targets, 0, 2, MSG_TURN_ON);
  177. }
  178.  
  179.  /* turn off the selected X10 units */
  180.  
  181. void X10TurnOff(STRPTR * Targets)
  182. {
  183.     OnOffDimHandler(Targets, 0, 3, MSG_TURN_OFF);
  184. }
  185.  
  186.  /* set the selected targets to the specified dim level */
  187.  
  188. void X10Dim(STRPTR * Targets, ULONG DimLevel)
  189. {
  190.     if (DimLevel < 1 || DimLevel > 16) {
  191.         ErrorMsg(MSG_INVALID_DIM_LEVEL, DimLevel);
  192.         return;
  193.     }
  194.  
  195.     DimLevel--;
  196.  
  197.     OnOffDimHandler(Targets, DimLevel, 5, MSG_DIM);
  198. }
  199.  
  200.  /* loop that handles X10TurnOn, X10TurnOff and X10Dim */
  201.  
  202. void OnOffDimHandler(STRPTR * Targets, ULONG DimLevel, ULONG Function, LONG Msg)
  203. {
  204.     int hc;
  205.     int unit;
  206.     UBYTE *currentTarget;
  207.  
  208.     if (!Targets)
  209.         ErrorMsg(MSG_NO_UNITS_SPECIFIED);
  210.     else
  211.         do {
  212.             currentTarget = *Targets;
  213.  
  214.             hc = X10GetHC(*currentTarget++);
  215.  
  216.             if (hc == -1)
  217.                 ErrorMsg(MSG_INVALID_UNIT, *Targets);
  218.             else {
  219.                 unit = atol(currentTarget);
  220.  
  221.                 if (unit < 1 || unit > 16)
  222.                     ErrorMsg(MSG_INVALID_UNIT, *Targets);
  223.                 else {
  224.                     unit--;
  225.                     if (!(X10SendDirectCmd(hc, unit, Function, DimLevel)))
  226.                         ErrorMsg(MSG_CP290_ERROR_DIRECT, GetString(&LocaleInfo, Msg), *Targets);
  227.                 }
  228.             }
  229.  
  230.             Targets++;
  231.  
  232.         } while (*Targets);
  233. }
  234.  
  235.  /* set the base housecode for the buttons on the controller unit */
  236.  
  237. void X10SetBaseHC(STRPTR BaseHC)
  238. {
  239.     int hc;
  240.     UBYTE Buf[18];
  241.  
  242.     if (!BaseHC)
  243.         ErrorMsg(MSG_NO_BASE_HC);
  244.     else {
  245.         hc = X10GetHC(BaseHC[0]);
  246.  
  247.         if (hc == -1)
  248.             ErrorMsg(MSG_INVALID_BASE_HC, BaseHC[0]);
  249.         else {
  250.             memset(Buf, 0xFF, 16);
  251.             Buf[16] = 0;
  252.             Buf[17] = HouseCode[hc];
  253.  
  254.             ClearSerial();
  255.             SerWrite(Buf, 18);
  256.             if (!X10WaitForAck(FALSE))
  257.                 ErrorMsg(MSG_CP290_ERROR_BASEHC);
  258.         }
  259.     }
  260. }
  261.  
  262.  /* set the controller unit's clock */
  263.  
  264. void X10SetClock(void)
  265. {
  266.     UBYTE Buf[21];
  267.     struct timeval tr_time;
  268.     ULONG secs;
  269.     int DOW;
  270.  
  271.     GetSysTime(&tr_time);
  272.     secs = tr_time.tv_secs % SECSINDAY;
  273.  
  274.     memset(Buf, 0xFF, 16);
  275.     Buf[16] = 2;
  276.  
  277.     Buf[18] = secs / SECSINHOUR;
  278.     secs %= SECSINHOUR;
  279.     Buf[17] = secs / SECSINMINUTE;
  280.  
  281.     DOW = ((tr_time.tv_secs / SECSINDAY) % 7) - 1;
  282.     if (DOW == -1)
  283.         DOW = 6;
  284.  
  285.     Buf[19] = 1L << DOW;
  286.  
  287.     Buf[20] = Buf[17] + Buf[18] + Buf[19];
  288.  
  289.     ClearSerial();
  290.     SerWrite(Buf, 21);
  291.     if (!X10WaitForAck(FALSE))
  292.         ErrorMsg(MSG_CP290_ERROR_SETCLOCK);
  293. }
  294.  
  295.  /* runs a diagnostic test on the x10 interface */
  296.  
  297. void X10Diagnostic(void)
  298. {
  299.     UBYTE Buf[17];
  300.     int index;
  301.     UWORD raw;
  302.     UBYTE BaseHC;
  303.     STRPTR DOW;
  304.  
  305.     /*
  306.      * send the code for a self diagnostic and wait for the unit's
  307.      * response
  308.      */
  309.  
  310.     memset(Buf, 0xFF, 16);
  311.     Buf[16] = 7;
  312.  
  313.     ClearSerial();
  314.     SerWrite(Buf, 17);
  315.  
  316.     for (index = 0;; index++) {
  317.         raw = SerGetRawChar(15);
  318.  
  319.         if (raw == TIMEOUT) {
  320.             ErrorMsg(MSG_CP290_ERROR_DIAG, GetString(&LocaleInfo, MSG_TIMEOUT));
  321.             return;
  322.         }
  323.  
  324.         if (raw == 0xFF)
  325.             index++;
  326.         else if (index > 5)
  327.             if ((raw & 1) == 1) {
  328.                 ErrorMsg(MSG_CP290_ERROR_DIAG, GetString(&LocaleInfo, MSG_STATUS_FLAG));
  329.                 return;
  330.             }
  331.             else
  332.                 break;
  333.     }
  334.  
  335.     /*
  336.      * if the interface passed the diagnositc test then query it about
  337.      * the base housecode and what time it thinks it is and display this
  338.      * to the user as part of the status message.
  339.      */
  340.  
  341.     memset(Buf, 0xFF, 16);
  342.     Buf[16] = 4;
  343.  
  344.     ClearSerial();
  345.     SerWrite(Buf, 17);
  346.  
  347.     for (index = 0;;) {
  348.         raw = SerGetRawChar(15);
  349.  
  350.         if (raw == TIMEOUT) {
  351.             ErrorMsg(MSG_CP290_ERROR_NO_RESPONSE);
  352.             return;
  353.         }
  354.  
  355.         if (raw == 0xFF) {
  356.             Buf[index++] = raw;
  357.             break;
  358.         }
  359.     }
  360.  
  361.     while (index < 12) {
  362.         raw = SerGetRawChar(2);
  363.  
  364.         if (raw == TIMEOUT) {
  365.             ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_TIMEOUT));
  366.             return;
  367.         }
  368.  
  369.         Buf[index++] = raw;
  370.     }
  371.  
  372.     if (Buf[11] != Buf[7] + Buf[8] + Buf[9] + Buf[10]) {
  373.         ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_CHECKSUM));
  374.         return;
  375.     }
  376.  
  377.     for (index = 0; index < 16; index++)
  378.         if (HouseCode[index] == Buf[10])
  379.             BaseHC = 'A' + index;
  380.  
  381.     switch (Buf[9]) {
  382.     case 64:
  383.         if (LocaleBase)
  384.             DOW = GetLocaleStr(DefaultLocale, DAY_1);
  385.         else
  386.             DOW = "Sunday";
  387.         break;
  388.  
  389.     case 32:
  390.         if (LocaleBase)
  391.             DOW = GetLocaleStr(DefaultLocale, DAY_7);
  392.         else
  393.             DOW = "Saturday";
  394.         break;
  395.  
  396.     case 16:
  397.         if (LocaleBase)
  398.             DOW = GetLocaleStr(DefaultLocale, DAY_6);
  399.         else
  400.             DOW = "Friday";
  401.         break;
  402.  
  403.     case 8:
  404.         if (LocaleBase)
  405.             DOW = GetLocaleStr(DefaultLocale, DAY_5);
  406.         else
  407.             DOW = "Thursday";
  408.         break;
  409.  
  410.     case 4:
  411.         if (LocaleBase)
  412.             DOW = GetLocaleStr(DefaultLocale, DAY_4);
  413.         else
  414.             DOW = "Wednesday";
  415.         break;
  416.  
  417.     case 2:
  418.         if (LocaleBase)
  419.             DOW = GetLocaleStr(DefaultLocale, DAY_3);
  420.         else
  421.             DOW = "Tuesday";
  422.         break;
  423.  
  424.     case 1:
  425.         if (LocaleBase)
  426.             DOW = GetLocaleStr(DefaultLocale, DAY_2);
  427.         else
  428.             DOW = "Monday";
  429.         break;
  430.  
  431.     default:
  432.         DOW = "???";
  433.         break;
  434.     };
  435.  
  436.     MyPrintf(MSG_CP290_PASSED_DIAG, BaseHC, DOW, Buf[8], Buf[7]);
  437.  
  438.     /*
  439.      * when a diagnostic is run, the interface whacks out all of its
  440.      * memory.  Thus, if we tried to upload data from it we would get
  441.      * garbage.  we also have garbage sitting there that might cause
  442.      * funny events to happen.  So we set the unit's base housecode to
  443.      * what we were just told it was by the interface.  This causes the
  444.      * interface to properly reset its memory so that we don't have bogus
  445.      * data sitting in it.
  446.      */
  447.     sprintf(Buf, "%lc", BaseHC);
  448.     X10SetBaseHC(Buf);
  449.  
  450.     return;
  451. }
  452.  
  453.  /*
  454.   * look at the character passed in and decide if it's a valid house code or
  455.   * not.  translate it into the appripriate index value for use with the
  456.   * controller unit if it's valid.  else return -1.
  457.   */
  458.  
  459. int X10GetHC(UBYTE Char)
  460. {
  461.     if (isalpha(Char)) {
  462.         Char = tolower(Char);
  463.  
  464.         if (Char >= 'a' && Char <= 'p')
  465.             return Char - 'a';
  466.     }
  467.  
  468.     return -1;
  469. }
  470.  
  471.  /* build an x10 direct command to turn a specified unit on, off, etc. */
  472.  
  473. BOOL X10SendDirectCmd(int HC, int Unit, ULONG Function, ULONG DimLevel)
  474. {
  475.     UBYTE Buf[22];
  476.     int unitByte;
  477.  
  478.     memset(Buf, 0xFF, 16);
  479.     Buf[16] = 1;
  480.     Buf[17] = ((DimLevel & 0x0F) << 4L) | (Function & 0x0F);
  481.     Buf[18] = HouseCode[HC];
  482.  
  483.     if (Unit < 8) {
  484.         Buf[19] = 0;
  485.         unitByte = 20;
  486.     }
  487.     else {
  488.         Buf[20] = 0;
  489.         unitByte = 19;
  490.         Unit -= 8;
  491.     }
  492.  
  493.     Buf[unitByte] = 1L << (7 - Unit);
  494.  
  495.     Buf[21] = Buf[17] + Buf[18] + Buf[19] + Buf[20];
  496.  
  497.     ClearSerial();
  498.     SerWrite(Buf, 22);
  499.     return X10WaitForAck(TRUE);
  500. }
  501.  
  502.  /*
  503.   * wait for the ack message from the controller unit.  we return the ack's
  504.   * status bit as either true or false
  505.   */
  506.  
  507. BOOL X10WaitForAck(BOOL WaitForUploadReport)
  508. {
  509.     int SYNCs;
  510.     UWORD raw;
  511.  
  512.     /* look for ack to our command */
  513.     for (SYNCs = 0; SYNCs < 16; SYNCs++) {
  514.         raw = SerGetRawChar(15);
  515.  
  516.         if (raw == TIMEOUT)
  517.             return FALSE;
  518.  
  519.         if (raw != 0xFF)
  520.             SYNCs = 255;
  521.     }
  522.  
  523.     if (WaitForUploadReport) {
  524.         /* look for upload report */
  525.         for (SYNCs = 0; SYNCs < 16; SYNCs++) {
  526.             raw = SerGetRawChar(15);
  527.  
  528.             if (raw == TIMEOUT)
  529.                 return FALSE;
  530.  
  531.             if (raw != 0xFF)
  532.                 SYNCs = 255;
  533.         }
  534.  
  535.         /* suck the remaining characters in the upload report */
  536.         do {
  537.             raw = SerGetRawChar(1);
  538.         } while (raw != TIMEOUT);
  539.     }
  540.  
  541.     return TRUE;
  542. }
  543.